package com.yk.system.listener;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import com.yk.api.dataGatherer.dto.CustomDTO;
import com.yk.api.dataGatherer.dto.DeviceParamDTO;
import com.yk.api.dataGatherer.dto.VariableParamDTO;
import com.yk.api.dataGatherer.model.RemoteTdEngineService;
import com.yk.common.core.constant.NumberConstant;
import com.yk.common.core.domain.Result;
import com.yk.common.core.utils.HutoolExcelUtil;
import com.yk.common.core.utils.file.FileUtils;
import com.yk.common.rabbitmq.constant.QueueConstants;
import com.yk.system.entity.ExcelHistory;
import com.yk.system.service.ExcelHistoryService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.x.file.storage.core.FileStorageService;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

/**
 * 自定义报表监听器
 *
 * @author lmx
 * @date 2023/12/26 11:30
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class CustomExcelListener {

    private final RemoteTdEngineService remoteTdEngineService;
    private final FileStorageService fileStorageService;
    private final ExcelHistoryService excelHistoryService;

    @RabbitListener(queues = QueueConstants.REPORT_EXPORT)
    @RabbitHandler
    public void onMessage(CustomDTO customDTO) {
        Long excelHistoryId = customDTO.getExcelHistoryId();
        if (Objects.isNull(excelHistoryId)) {
            return;
        }
        ExcelHistory excelHistory = excelHistoryService.getById(excelHistoryId);
        if (Objects.isNull(excelHistory)) {
            return;
        }
        Result<Map<String, List<Map<String, Object>>>> result = remoteTdEngineService.getCustomReportData(customDTO);
        if (!result.isSuccess()) {
            excelHistory.setStatus(NumberConstant.THREE_STR);
            excelHistoryService.updateById(excelHistory);
            return;
        } else {
            excelHistory.setStatus(NumberConstant.ONE_STR);
            excelHistoryService.updateById(excelHistory);
        }
        List<List<String>> rows = CollUtil.newArrayList();
        Map<String, List<Map<String, Object>>> data = result.getData();
        // 获取设备名称
        Map<String, String> deviceMap = customDTO.getDevices().stream().collect(Collectors.toMap(DeviceParamDTO::getDeviceId, DeviceParamDTO::getDeviceName));
        // 获取变量名称
        Map<String, String> variableMap = customDTO.getVariables().stream().collect(Collectors.toMap(VariableParamDTO::getUrl, VariableParamDTO::getName));
        // 二级表头
        Set<String> deviceSet = deviceMap.keySet();
        Set<String> variableSet = variableMap.keySet();
        List<String> headList = CollUtil.newArrayList();
        headList.add("序号");
        headList.add("设备");
        List<String> headTwoList = CollUtil.newArrayList();
        headTwoList.add("序号");
        headTwoList.add("变量");
        for (String s : deviceSet) {
            for (String s2 : variableSet) {
                headList.add(deviceMap.get(s));
                headTwoList.add(variableMap.get(s2));
            }
        }
        rows.add(headTwoList);
        if (MapUtil.isNotEmpty(data)) {
            buildExcel(rows, data, deviceSet, variableSet);
        }
        ExcelWriter writer = ExcelUtil.getWriter(true);
        writer.writeHeadRow(headList);
        writer.write(rows);
        writer.merge(0, 1, 0, 0, headList.get(0), true);
        // 单个设备
        if (headList.size() > NumberConstant.THREE && deviceMap.size() < NumberConstant.TWO) {
            extracted(headList, writer);
        }
        // 多个设备
        if (headList.size() > NumberConstant.FOUR && deviceMap.size() > NumberConstant.ONE) {
            extracted(headList, writer);
        }
        HutoolExcelUtil.setBaseStyle(writer);
        try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
            writer.flush(out);
            writer.close();
            // Excel历史表更新
            excelHistory.setStatus(NumberConstant.TWO_STR);
            excelHistoryService.updateById(excelHistory);
            fileStorageService.of(new ByteArrayInputStream(out.toByteArray()), null, null, (long) out.size())
                    .setSaveFilename(customDTO.getExcelName() + ".xlsx")
                    .setObjectId(excelHistory.getId())
                    .setPath(FileUtils.getPrefix())
                    .upload();
        } catch (Exception e) {
            log.error("自定义报表失败", e.getMessage());
        }
    }

    /**
     * 合并 选择范围至少要两个cell要不会报错
     * @param headList
     * @param writer
     */
    private void extracted(List<String> headList, ExcelWriter writer) {
        int startCol = 0, lastCol = 0;
        String deviceName = null;
        int lastColumn = 1;
        for (int i = 2; i < headList.size(); i++){
            if (headList.get(i).equals(deviceName)){
                continue;
            }
            deviceName = headList.get(i);
            String finalDeviceName = deviceName;
            int count = (int) headList.stream().filter(it -> it.equals(finalDeviceName)).count();
            lastColumn = lastColumn + count ;
            writer.merge(startCol, lastCol, i, lastColumn, deviceName, true);
        }
    }

    /**
     * 表格构建
     *
     * @param rows        转换的列表
     * @param data        数据列表
     * @param deviceSet   设备名列表
     * @param variableSet 变量名列表
     */
    private void buildExcel(List<List<String>> rows, Map<String, List<Map<String, Object>>> data,
                            Set<String> deviceSet, Set<String> variableSet) {
        // 行数据
        Set<String> set = data.keySet();
        AtomicInteger index = new AtomicInteger(1);
        for (String date : set) {
            List<String> row = CollUtil.newArrayList();
            // 序号
            row.add(String.valueOf(index.getAndIncrement()));
            // 时间
            row.add(date);
            // 历史数据
            List<Map<String, Object>> dataList = data.get(date);
            // 设备
            for (String device : deviceSet) {
                // 变量名称
                for (String variable : variableSet) {
                    Optional<Map<String, Object>> firstMap = dataList.stream().filter(it -> it.get("device_id").toString().equals(device)).findFirst();
                    if (firstMap.isPresent()) {
                        Map<String, Object> stringObjectMap = firstMap.get();
                        // 变量值
                        if (Objects.nonNull(stringObjectMap.get(variable))) {
                            String s1 = stringObjectMap.get(variable).toString();
                            row.add(s1);
                        }else {
                            row.add("");
                        }
                    } else {
                        row.add("");
                    }
                }
            }
            rows.add(row);
        }
    }
}
